#define JMBC_INSIDE
#include "ilPNG.h"
#include "ilImage.h"
#include <Math/mlMath.h>
#include <Core/clCore.h>
#include <stdio.h>
#include <png.h>
#include <GL/glu.h>

void
ilImageLoadPNG(unsigned int id, unsigned int filepath)
{
	FILE *stream;
	char tmp[256];

	//stream = _wfopen(tlStringData(filepath), L"rb");
	wcstombs(tmp, tlStringData(filepath), 256);
	stream = fopen(tmp, "rb");

	if(stream)
	{
		unsigned char signature[8]; 

		fread(signature, 1, 8, stream);

		if(png_check_sig(signature, 8))
		{
			png_structp png;

			png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

			if(png)
			{
				png_infop info;

				info = png_create_info_struct(png);

				if(info)
				{
					if(!setjmp(png_jmpbuf(png)))
					{
						ILImage *image;
						png_bytepp rows;
						int depth, type;
						png_uint_32 width, height;
						unsigned long i;

						image = ilImageStore(id);

						png_init_io(png, stream);
						png_set_sig_bytes(png, 8);
						png_read_info(png, info);

						png_get_IHDR(png, info, &width, &height, &depth, &type, NULL, NULL, NULL);

						if(depth > 8)
							png_set_strip_16(png);

						switch(type)
						{
							case PNG_COLOR_TYPE_GRAY:
							case PNG_COLOR_TYPE_GRAY_ALPHA:
								png_set_gray_to_rgb(png);
							break;
							case PNG_COLOR_TYPE_PALETTE:
								png_set_palette_to_rgb(png);
							break;
							default:
							break;
						}
								
/*
						if(type == PNG_COLOR_TYPE_GRAY || type == PNG_COLOR_TYPE_GRAY_ALPHA)
							png_set_gray_to_rgb(png);

						if(type == PNG_COLOR_TYPE_PALETTE)
							png_set_palette_to_rgb(png);
*/

						png_read_update_info(png, info);

						image->width = mlNextTwoPower((float) width);
						image->height = mlNextTwoPower((float) height);
						image->bpp = (type & PNG_COLOR_MASK_ALPHA) ? 4 : 3;
						image->pixels = malloc(image->width * image->height * image->bpp * sizeof(unsigned char));

						rows = malloc(height * sizeof(png_bytep));
						for(i = 0; i < height; i++)
							rows[height - 1 - i] = image->pixels + i * width * image->bpp;
						png_read_image(png, rows);
						free(rows);

						if(width != image->width || height != image->height)
							gluScaleImage(ilImageBPPToFormat(image->bpp), width, height, GL_UNSIGNED_BYTE, image->pixels, image->width, image->height, GL_UNSIGNED_BYTE, image->pixels);
					}
					else
						elErrorSet(EL_ERROR_INVALID);

					png_destroy_read_struct(&png, &info, NULL);
				}
				else
				{
					png_destroy_read_struct(&png, (png_infopp) NULL, (png_infopp) NULL);
					elErrorSet(EL_ERROR_INVALID);
				}
			}
			else
				elErrorSet(EL_ERROR_INVALID);
		}
		else
			elErrorSet(EL_ERROR_INVALID);

		fclose(stream);
	}
	else
		elErrorSet(EL_ERROR_INVALID);
}

void
ilImageSavePNG(unsigned int id, unsigned int filepath)
{
	FILE *stream;
	char tmp[256];

	//stream = _wfopen(tlStringData(filepath), L"wb");
	wcstombs(tmp, tlStringData(filepath), 256);
	stream = fopen(tmp, "wb");

	if(stream)
	{
		png_structp png;

		png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

		if(png)
		{
			png_infop info;

			info = png_create_info_struct(png);

			if(info)
			{
				if(!setjmp(png_jmpbuf(png)))
				{
					ILImage *image;
					png_bytepp rows;
					unsigned long i;

					image = ilImageStore(id);

					png_init_io(png, stream);
					png_set_IHDR(png, info, image->width, image->height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
					png_write_info(png, info);

					rows = malloc(image->height * sizeof(png_bytep));
					for(i = 0; i < image->height; i++)
						rows[image->height - 1 - i] = image->pixels + i * image->width * image->bpp;
					png_write_image(png, rows);
					free(rows);

					png_write_end(png, info);
				}
				else
					elErrorSet(EL_ERROR_INVALID);

				png_destroy_write_struct(&png, &info);
			}
			else
			{
				png_destroy_write_struct(&png, (png_infopp) NULL);
				elErrorSet(EL_ERROR_INVALID);
			}
		}
		else
			elErrorSet(EL_ERROR_INVALID);

		fclose(stream);
	}
	else
		elErrorSet(EL_ERROR_INVALID);
}
